﻿using UnityEngine;
using System.Collections.Generic;
using RestSharp;

public static class SparkExtensions
{

    public static T GetRandomItem<T>(this List<T> items) where T : class
    {

        System.Random rnd = new System.Random();
        return items[rnd.Next(items.Count)];
    }

    public static string GetRootPath(this Transform trans, Transform rootTrans)
    {
        return GetPathRecursive(string.Empty, trans, rootTrans);
    }

    private static string GetPathRecursive(string path, Transform trans, Transform rootTrans)
    {
        string slash = path == string.Empty ? string.Empty : "/";
        path = trans.name + slash + path;
        if (trans.parent == rootTrans)
        {
            return path;
        }
        else
        {
            return GetPathRecursive(path, trans.parent, rootTrans);
        }
    }

    public static string Clamp(this string str, int length)
    {
        if (str.Length > length)
        {
            return str.Substring(0, length);
        }
        else
        {
            return str;
        }
    }

    public static void SetPosition(this GameObject gameObj, Vector3 trans)
    {
        gameObj.transform.position = trans;
    }

    public static void DestroyAllChildren(this Transform tran)
    {
        for (int i = 0; i < tran.childCount; i++)
        {
            Object.Destroy(tran.GetChild(i).gameObject);
        }
    }

    public static T GetSafeComponent<T>(this GameObject obj) where T : MonoBehaviour
    {
        T component = obj.GetComponent<T>();

        if (component == null)
        {
            Debug.LogError("Expected to find component of type "
                    + typeof(T) + " but found none", obj);
        }

        return component;
    }

    public static T GetInterfaceComponent<T>(this MonoBehaviour script) where T : MonoBehaviour
    {
        return script.GetComponent(typeof(T)) as T;
    }

    public static T GetInterfaceComponent<T>(this GameObject obj) where T : MonoBehaviour
    {
        return obj.GetComponent(typeof(T)) as T;
    }

    public static List<I> FindObjectsOfInterface<I>(Object obj) where I : MonoBehaviour
    {
        MonoBehaviour[] monoBehaviours = Object.FindObjectsOfType<MonoBehaviour>();
        List<I> list = new List<I>();

        foreach (MonoBehaviour behaviour in monoBehaviours)
        {
            I component = behaviour.GetComponent(typeof(I)) as I;

            if (component != null)
            {
                list.Add(component);
            }
        }

        return list;
    }

    public static GameObject Clone(this GameObject obj)
    {
        return (GameObject)GameObject.Instantiate(obj);
    }

    public static GameObject Clone(this GameObject obj, Vector3 position, Quaternion rotation)
    {
        return (GameObject)GameObject.Instantiate(obj, position, rotation);
    }

    public static void setParent(this GameObject obj, Transform parent)
    {
        Transform trans = obj.transform;
        trans.parent = parent;
        trans.localPosition = Vector3.zero;
        trans.localScale = Vector3.one;
        trans.localRotation = Quaternion.identity;
    }
    /// <summary>
    /// 把obj ，加到 parent上，并设置obj位置
    /// 设置父物体，并修改其位置
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="obj"></param>
    public static void setParent(this GameObject obj, GameObject parent, float posX, float posY)
    {
        Transform trans = obj.transform;
        trans.parent = parent.transform;
        trans.localPosition = new Vector2(posX, posY);
        trans.localScale = Vector3.one;
        trans.localRotation = Quaternion.identity;
    }
    public static void Push<T>(this List<T> list, T obj) where T : class
    {
        list.Add(obj);
    }

    public static T Pop<T>(this List<T> list) where T : class
    {
        if (list.Count > 0)
        {
            T item = list[list.Count - 1];
            list.Remove(item);
            return item;
        }
        else
        {
            return default(T);
        }
    }

    public static GameObject FindChild(this GameObject parent, string name)
    {
        Transform trans = parent.transform.Find(name);
        if (trans == null)
        {
            Debug.Log("Not found: " + name);
            // Debug.LogError("Not found: " + name);
            return null;
        }
        else
            return trans.gameObject;
    }
    /// <summary>
    /// 在父物体上找到子物体，更改其文本
    /// </summary>
    /// <param name="parent"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    public static void SetChildText(this GameObject parentObj, string childName, string childText)
    {
        GameObject gameObj = FindChild(parentObj, childName);

        if (gameObj != null)
        {
            gameObj.GetComponent<UILabel>().text = childText;
        }


    }

    public static GameObject FindDescendant(this GameObject parent, string name)
    {
        if (parent.name == name) return parent;
        Transform trans = parent.transform;
        foreach (Transform t in trans)
        {
            GameObject result = t.gameObject.FindDescendant(name);
            if (result != null) return result;
        }
        return null;
    }



    /// <summary>
    /// 取一个随机元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <returns></returns>
    public static T PickRandom<T>(this List<T> list)
    {
        return list[SparkRandom.Random.Next(list.Count)];
    }

    /// <summary>
    /// 取一个不等于指定对象的元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="exclude"></param>
    /// <returns></returns>
    public static T PickRandomExclude<T>(this List<T> list, T exclude)
    {
        int count = list.Count;
        if (list.Empty())
        {
            return default(T);
        }
        if (list.Count == 1 && list[0].Equals(exclude))
        {
            return default(T);
        }
        int index = SparkRandom.Random.Next(count);
        T target = list[index];
        if (target.Equals(exclude))
        {
            if (index == list.Count - 1)
            {
                target = list[index - 1];
            }
            else
            {
                target = list[index + 1];
            }
        }
        return target;
    }

    /// <summary>
    /// 该列表是否为空
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <returns></returns>
    public static bool Empty<T>(this List<T> list)
    {
        return list.Count == 0;
    }

    /// <summary>
    /// 附加一个冲量
    /// </summary>
    /// <param name="rigidBody2D"></param>
    /// <param name="impulse"></param>
    public static void ApplyImpulse(this Rigidbody2D rigidBody2D, Vector2 impulse)
    {
        Vector2 force = impulse / Time.fixedDeltaTime;
        Debug.LogWarning(force);
        rigidBody2D.AddForce(force);
    }

    public static Coroutine StartSparkCoroutine(this MonoBehaviour script, System.Func<System.Collections.IEnumerator> coroutine)
    {
        return script.StartCoroutine(SparkCoroutineManager.Run(coroutine()));
    }

    public static Coroutine StartSparkCoroutine(this MonoBehaviour script, System.Collections.IEnumerator coroutine)
    {
        return script.StartCoroutine(SparkCoroutineManager.Run(coroutine));
    }


    public static void addEffect(this MonoBehaviour script, GameObject parent, string effectResPath, float duration)
    {
        GameObject effect = Resources.Load<GameObject>(effectResPath);
        effect.transform.parent = parent.transform;
        effect.transform.localPosition = Vector3.zero;
        effect.transform.localRotation = Quaternion.identity;
        effect.transform.localScale = Vector3.one;
        script.Invoke("DestroyMe", duration);
    }

    public static void postNotification(this MonoBehaviour script, System.Enum evt, object arg)
    {
        NotificationCenter.DefaultCenter().PostNotification(script, evt.ToString(), arg);
    }

    public static void Put(this System.Collections.Hashtable ht, object key, object value)
    {
        if (ht.ContainsKey(key))
        {
            ht[key] = value;
        }
        else
        {
            ht.Add(key, value);
        }
    }

    public static int OptInt(this System.Collections.Hashtable ht, string key, int defaultValue)
    {
        if (ht.ContainsKey(key))
        {
            try
            {
                return System.Convert.ToInt32(ht[key]);
            }
            catch (System.Exception ex)
            {
                Debug.LogWarning("Error get member: " + key + ";" + ex.Message);
                return defaultValue;
            }
        }
        else
        {
            return defaultValue;
        }
    }

    public static int OptInt(this System.Collections.Hashtable ht, string key)
    {
        return ht.OptInt(key, 0);
    }

    public static string OptString(this System.Collections.Hashtable ht, string key)
    {
        return ht.OptString(key, string.Empty);
    }

    public static string OptString(this System.Collections.Hashtable ht, string key, string defaultValue)
    {
        if (ht.ContainsKey(key))
        {
            try
            {
                return ht[key].ToString();
            }
            catch (System.Exception ex)
            {
                Debug.LogWarning("Error get member: " + key + ";" + ex.Message);
                return defaultValue;
            }
        }
        else
        {
            return defaultValue;
        }
    }

    public static bool OptBool(this System.Collections.Hashtable ht, string key, bool defaultValue)
    {
        try
        {
            if (ht.ContainsKey(key))
            {
                return System.Convert.ToBoolean(ht[key]);
            }
            else
            {
                return defaultValue;
            }
        }
        catch (System.Exception ex)
        {
            Debug.LogWarning("Error get member: " + key + ";" + ex.Message);
            return defaultValue;
        }
    }

    public static bool OptBool(this System.Collections.Hashtable ht, string key)
    {
        return ht.OptBool(key, false);
    }
    public static double OptDouble(this System.Collections.Hashtable ht, string key, double defaultValue)
    {
        if (ht.ContainsKey(key))
        {
            try
            {
                return System.Convert.ToDouble(ht[key]);
            }
            catch (System.Exception ex)
            {
                Debug.LogWarning("Error get member: " + key + ";" + ex.Message);
                return defaultValue;
            }
        }
        else
        {
            return defaultValue;
        }
    }

    public static double OptDouble(this System.Collections.Hashtable ht, string key)
    {
        return ht.OptDouble(key, 0);
    }

    public static T Opt<T>(this JsonObject jObj, string key, T defaultValue)
    {
        if (jObj.ContainsKey(key))
        {
            object value = jObj[key];
            if (value.GetType().IsAssignableFrom(typeof(T)))
            {
                return (T)value;
            }
            else
            {
                Debug.LogError("无法强制转换: 从(" + value + ")" + value.GetType() + "到" + typeof(T));
                return defaultValue;
            }

        }
        else
        {
            return defaultValue;
        }
    }

    public static T Opt<T>(this JsonObject jObj, string key)
    {
        return jObj.Opt<T>(key, default(T));
    }

    public static T Get<T>(this JsonArray jArray, int index, T defaultValue)
    {
        return (T)jArray[index];
    }
    /// <summary>
    /// 方法只能写在animator上的gameobject的任何一个monoBehaviour，在animator上的layerIndex层的某个state animation的第frameIndex帧上addEvent，funName是函数名，value是参数
    /// </summary>
    /// <param name="layerIndex"></param>
    /// <param name="aniName"></param>
    /// <param name="frameIndex"></param>
    public static void AddKeyEventFromAnimator<T>(this Animator animator, int layerIndex, string stateName, int frameIndex, string funcName, T value)
    {
        UnityEditorInternal.AnimatorController ac = animator.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
        UnityEditorInternal.StateMachine sm = ac.GetLayer(layerIndex).stateMachine;
        for (int i = 0; i < sm.stateCount; i++)
        {
            UnityEditorInternal.State state = sm.GetState(i);
            if (state.name.Equals(stateName))
            {
                AnimationClip clip = state.GetMotion() as AnimationClip;
                UnityEngine.AnimationEvent evt = new UnityEngine.AnimationEvent();
                evt.functionName = funcName;
                evt.messageOptions = SendMessageOptions.DontRequireReceiver;
                evt.time = frameIndex / clip.frameRate;
                if (value is int)
                {
                    evt.intParameter = System.Convert.ToInt32(value);
                }
                else if (value is float)
                {
                    evt.floatParameter = System.Convert.ToSingle(value);
                }
                else if (value is string)
                {
                    evt.stringParameter = value as string;
                }
                else if (value is Object)
                {
                    evt.objectReferenceParameter = value as Object;
                }
                else
                {
                    Debug.LogWarning("参数非法，无法再animator上增加帧事件");
                }
                clip.AddEvent(evt);
                break;
            }
        }
    }
}
